package com.kulian.Signalling.distribution.utils;

import com.kulian.Signalling.distribution.vo.PackageVO;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class FileDownloadUtil {
    private static final Logger logger = LoggerFactory.getLogger(FileDownloadUtil.class);
    private static final int BUFFER_SIZE = 64 * 1024; // 64KB缓冲区

    /**
     * 安全下载文件方法
     * @param response HttpServletResponse
     * @param file 要下载的文件
     * @param deleteAfterDownload 下载后是否删除文件
     */
    public static void safeDownload(HttpServletResponse response, File file, boolean deleteAfterDownload, PackageVO packageVO) {
        if (file == null || !file.exists() || !file.canRead()) {
            sendError(response, HttpServletResponse.SC_NOT_FOUND, "文件不存在或不可读");
            return;
        }

        // 设置响应头
        setResponseHeaders(response, file.getName(), file.length(),packageVO);

        try (InputStream is = new FileInputStream(file);
             OutputStream os = response.getOutputStream()) {

            copyStream(is, os);

            if (deleteAfterDownload) {
                deleteFileSilently(file);
            }

        } catch (IOException e) {
            handleDownloadException(e, response);
        }
    }

    private static void setResponseHeaders(HttpServletResponse response, String fileName, long fileLength,PackageVO packageVO) {
        if (!response.isCommitted()) {
            try {

                if (packageVO.getPlatform() == "ios"){
                    response.setContentType("application/force-download");
                    response.setHeader("Content-Disposition", "attachment;fileName=manifest.plist");
                }else {
                    response.setContentType("application/octet-stream");
                    response.setHeader("Content-Disposition", "attachment; filename=\"" + encodeFileName(fileName) + "\"");
                }
                response.setHeader("Content-Length", String.valueOf(fileLength));
                response.setBufferSize(BUFFER_SIZE);
            } catch (IllegalStateException e) {
                logger.debug("响应已提交，无法设置头信息");
            }
        }
    }

    private static String encodeFileName(String fileName) {
        try {
            return java.net.URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            return fileName;
        }
    }

    private static void copyStream(InputStream is, OutputStream os) throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead;

        while ((bytesRead = is.read(buffer)) != -1) {
            try {
                os.write(buffer, 0, bytesRead);
            } catch (IOException e) {
                if (isBrokenPipe(e)) {
                    logger.debug("客户端中断下载");
                    throw e; // 重新抛出，由上层处理
                }
                throw new IOException("写入响应流失败", e);
            }
        }
    }

    private static boolean isBrokenPipe(IOException e) {
        String message = e.getMessage();
        return message != null &&
                (message.contains("Broken pipe") ||
                        message.contains("Connection reset by peer") ||
                        message.contains("AsyncRequestNotUsableException"));
    }

    private static void handleDownloadException(Exception e, HttpServletResponse response) {
        if (isBrokenPipe((IOException) e)) {
            logger.debug("客户端中断连接: {}", e.getMessage());
            return;
        }

        logger.error("文件下载失败", e);
        if (!response.isCommitted()) {
            sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "文件下载失败");
        }
    }

    private static void sendError(HttpServletResponse response, int sc, String msg) {
        try {
            response.sendError(sc, msg);
        } catch (IOException e) {
            logger.error("发送错误响应失败", e);
        }
    }

    private static void deleteFileSilently(File file) {
        try {
            if (!file.delete()) {
                logger.warn("无法删除文件: {}", file.getAbsolutePath());
            }
        } catch (SecurityException e) {
            logger.warn("没有权限删除文件: {}", file.getAbsolutePath(), e);
        }
    }
}
